package top.huhuiyu.teachproject.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import top.huhuiyu.teachproject.base.BaseDataResult;
import top.huhuiyu.teachproject.base.BaseResult;
import top.huhuiyu.teachproject.dao.TbFileDAO;
import top.huhuiyu.teachproject.entity.AuthInfo;
import top.huhuiyu.teachproject.entity.TbFile;
import top.huhuiyu.teachproject.exception.AppException;
import top.huhuiyu.teachproject.service.FileService;
import top.huhuiyu.teachproject.utils.AuthInfoUtils;
import top.huhuiyu.teachproject.utils.JsonUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class FileServiceImpl implements FileService {

  public static final String FILE_PATH = "./upload/";
  private final TbFileDAO tbFileDAO;

  @Override
  @Transactional
  public BaseDataResult<TbFile> upload(TbFile tbFile, MultipartFile file) {
    AuthInfo authInfo = AuthInfoUtils.authInfo();
    log.debug("文件描述信息：{}", tbFile);
    log.debug("文件信息：{},{},{}", file.getContentType(), file.getOriginalFilename(), file.getSize());
    // 添加信息到数据，获取到主键信息
    tbFile.setUid(authInfo.getUserId());
    tbFile.setFilename(file.getOriginalFilename());
    tbFile.setContentType(file.getContentType());
    tbFile.setFilesize(file.getSize());
    int r = tbFileDAO.insert(tbFile);
    if (r != 1) {
      return BaseDataResult.failNoData("上传失败！无法添加信息到数据库。");
    }
    try {
      // 通过主键信息产生唯一文件名称
      String savename = String.format("__%s__%s", tbFile.getFid(), tbFile.getFilename());
      File savefile = new File(FILE_PATH, savename);
      // 确保路径存在
      File updir = new File(FILE_PATH);
      if (!updir.isDirectory()) {
        updir.mkdirs();
      }
      // 保存文件到服务器路径中
      InputStream is = file.getInputStream();
      OutputStream os = new FileOutputStream(savefile);
      byte[] buffer = new byte[8 * 1024];
      int len = is.read(buffer);
      while (len > 0) {
        os.write(buffer, 0, len);
        os.flush();
        len = is.read(buffer);
      }
      os.close();
      is.close();
      return BaseDataResult.ok("上传成功", tbFile);
    } catch (Exception ex) {
      // 如果操作发生异常，需要抛出异常来回滚事务
      throw AppException.getInstance(ex.getMessage());
    }
  }

  @Override
  public void download(Integer fid, HttpServletResponse response) {
    // 校验文件是否存在
    TbFile tbFile = tbFileDAO.selectById(fid);
    if (tbFile == null) {
      downloadError("文件信息不存在", response);
      return;
    }
    // 获取文件信息
    String savename = String.format("__%s__%s", tbFile.getFid(), tbFile.getFilename());
    File file = new File(FILE_PATH, savename);
    if (!file.isFile()) {
      downloadError("文件不存在", response);
      return;
    }
    // 下载文件
    response.setContentType(tbFile.getContentType());
    // 自定义下载文件名称
    response.setHeader("Content-Disposition", "attachment;filename=" + tbFile.getFilename());
    try (InputStream is = new FileInputStream(file)) {
      byte[] buffer = new byte[8 * 1024];
      int len = is.read(buffer);
      OutputStream os = response.getOutputStream();
      while (len>0) {
        os.write(buffer, 0, len);
        os.flush();
        len = is.read(buffer);
      }
      os.close();
    } catch (Exception ex) {
      downloadError("文件下载异常", response);
    }
  }

  public void downloadError(String error, HttpServletResponse response) {
    try {
      BaseResult result = BaseResult.fail(error);
      response.setCharacterEncoding("UTF-8");
      response.setContentType("text/plain");
      response.getWriter().println(JsonUtils.stringify(result));
      response.getWriter().close();
    } catch (Exception ex) {
      throw AppException.getInstance(ex.getMessage());
    }
  }

}
